/*
 * FilePath     : \src\views\scheduling\hooks\useSchedulingUniverUtil.ts
 * Author       : 苏军志
 * Date         : 2024-10-07 11:26
 * LastEditors  : 苏军志
 * LastEditTime : 2025-03-12 15:01
 * Description  : Univer组件针对排班 相关的方法
 * CodeIterationRecord:
 */
/* eslint-disable id-match */
import type { Ref } from "vue";
import type { FUniver } from "@univerjs/presets";
import type { FWorksheet, FRange } from "@univerjs/presets/preset-sheets-core";
import type { customMenuDataType, keyType } from "@/components/univerSheet/types/customMenuDataType";
import { useUniverUtil } from "@/components/univerSheet/hooks/useUniverUtil";
import type { configType } from "@/components/univerSheet/types/configType";
import { useSchedulingControl } from "./useSchedulingControl";
import { menuTypeEnum } from "../types/menuTypeEnum";
import univerMenuIcons, { menuIconEnum } from "../components/univerMenuIcon/index";
export function useSchedulingUniverUtil(
  config: configType,
  tableView: Ref<TableView>,
  isTemplate: boolean,
  restrictCapabilityLevel?: boolean,
  editRemark?: Function,
  selectTemplate?: Function
) {
  // 休假岗
  const restPostType: string = "4";
  // 备注标记ID
  const remarkID: number = 147;
  // 休假标记ID
  const restPostID: number = 180;
  const { getConfig, tableViewConvertCellData, cellBaseStyle } = useUniverUtil(config);
  /**
   * @description: 获取岗位、午别、标记菜单的KeyMap
   */
  const getKeyMaps = () => {
    let templateKeyMap: Record<keyType, string> = {
      id: "key",
      title: "value",
      tooltip: "value",
      icon: "icon"
    };
    let postKeyMap: Record<keyType, string> = {
      id: "value",
      title: "localLabel",
      tooltip: "label",
      icon: "icon"
    };
    let noonKeyMap: Record<keyType, string> = {
      id: "value",
      title: "label",
      tooltip: "tooltip",
      icon: "icon"
    };
    let markKeyMap: Record<keyType, string> = {
      id: "markID",
      title: "text",
      tooltip: "remark",
      icon: "icon"
    };
    return { templateKeyMap, postKeyMap, noonKeyMap, markKeyMap };
  };
  /**
   * @description: 判断是否禁用菜单（目前只针对层级限制正常岗位）
   * @param menuType 菜单类型
   * @param menuID 菜单ID
   * @param univerAPI
   * @return
   */
  const getMenuDisabled = (menuType: string, menuID: string | number, univerAPI: FUniver) => {
    const { headerRowCount } = getConfig();
    const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet();
    const { startRow, startColumn } = sheet?.getActiveRange()?.getRange() || {};
    if (startRow === undefined || startColumn === undefined) {
      return true;
    }
    if (isTemplate) {
      return false;
    }
    // 标题行、日统计、周排班月统计行并关闭提示
    if (
      startRow < headerRowCount ||
      startRow >= tableView.value.rows.length + headerRowCount ||
      startColumn >= tableView.value.columns.length
    ) {
      return true;
    }
    const employee = tableView.value.rows[startRow - headerRowCount].employee;
    if (!employee) {
      return true;
    }
    if (menuType.includes(menuTypeEnum.POST_MENU) && restrictCapabilityLevel && !employee.departmentPostIDs.includes(menuID)) {
      return true;
    }
    return false;
  };
  /**
   * @description: 判断菜单是否选择（目前只针对排班标记菜单的已选择回显）
   * @param menuType 菜单类型
   * @param menuID 菜单ID
   * @param univerAPI
   * @return
   */
  const getMenuActivated = (menuType: string, menuID: string | number, univerAPI: FUniver) => {
    if (menuType !== menuTypeEnum.MARK_MENU) {
      return false;
    }
    const { headerRowCount } = getConfig();
    const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet();
    const range = sheet?.getActiveRange()!;
    const { startRow, startColumn } = range.getRange();
    if (startRow === undefined || startColumn === undefined) {
      return false;
    }
    let markList = undefined;
    if (isTemplate) {
      markList = range.getCellData()?.custom?.markList;
    } else {
      const column = tableView.value.columns[startColumn];
      markList = tableView.value.rows[startRow - headerRowCount]?.[column?.key]?.markList;
    }
    if (markList?.length && markList.find((mark: Record<string, any>) => mark.markID === menuID)) {
      return true;
    }
    return false;
  };
  /**
   * @description: 同步带教学生排班
   * @param cellData 单元格数据
   * @param teacherRange 老师所属区域
   * @param sheet 工作簿实例
   * @return
   */
  const setStudentScheduling = (cellData: Record<string, any>, teacherRange: FRange, sheet: FWorksheet) => {
    const { headerRowCount } = getConfig();
    const { startRow, startColumn } = teacherRange.getRange();
    const teacherEmployeeID = tableView.value.rows[startRow - headerRowCount].employee.employeeID;
    // 防止失效，这里setTimeout不能删除
    setTimeout(() => {
      tableView.value.rows.forEach((row, index) => {
        if (row.employee.teacherEmployeeID === teacherEmployeeID) {
          const range = sheet.getRange(index + headerRowCount, startColumn, 1, 1);
          range?.setValue(cellData);
        }
      });
    }, 0);
  };
  /**
   * @description: 获取菜单单击回调方法
   * @param noonList 午别列表
   * @return
   */
  const getMenuItemCallback = (noonList: Record<string, string>[]) => {
    let getEmployeeSecondmentNoon: Function | undefined = undefined;
    let canScheduling: Function | undefined = undefined;
    if (!isTemplate) {
      const schedulingControl = useSchedulingControl(tableView.value);
      getEmployeeSecondmentNoon = schedulingControl.getEmployeeSecondmentNoon;
      canScheduling = schedulingControl.canScheduling;
    }
    /**
     * @description: 菜单单击回调方法
     * @param menuType 菜单类别
     * @param data 菜单选中的数据post/mark/template
     * @param univerAPI univerAPI实例
     * @return
     */
    return async (menuType: string, data: Record<string, any>, univerAPI: FUniver) => {
      const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet();
      const range = sheet?.getActiveRange();
      const { startRow, startColumn } = range?.getRange() || {};
      const cellData: Record<string, any> = range?.getCellData() as Record<string, any>;
      let noonPost: Record<string, Record<string, any>> = cellData?.custom?.noonPost || {};
      let markList: Record<string, any>[] = cellData?.custom?.markList || [];
      const isPostMenu = menuType.includes(menuTypeEnum.POST_MENU) || menuType.includes(menuTypeEnum.REST_MENU);
      let backgroundColor: string | undefined = undefined;
      let employeeSecondmentNoon: [string, string, string] | undefined = undefined;
      let rowIndex = startRow! - config.headerRowCount!;
      // 排班模板，调用父组件传入的方法处理
      if (menuType === menuTypeEnum.TEMPLATE_MENU) {
        selectTemplate && selectTemplate(data.key);
        return;
      }
      if (isPostMenu && data) {
        if (getEmployeeSecondmentNoon) {
          employeeSecondmentNoon = getEmployeeSecondmentNoon(rowIndex, startColumn);
          const column: TableColumn | undefined = tableView.value.columns.find((column) => column.index === Number(startColumn));
          const row = tableView.value.rows[rowIndex];
          if (column && row) {
            backgroundColor = getSecondBackGroundColor(row, row[column.key]);
          }
        }
        const post = data;
        let noonTypes: string[] = [];
        let noonType = "";
        // 从菜单类型解析出午别类型
        if (menuType.includes(menuTypeEnum.NOON_MENU)) {
          const menuTypeArr = menuType.split("-");
          noonType = menuTypeArr[menuTypeArr.length - 1];
        }
        // 如果传上午/下午，直接取
        if (noonType) {
          noonTypes.push(noonType);
        } else {
          // 没有传从字典中获取
          noonTypes = noonList.map((noon: Record<string, any>) => noon.value);
        }
        noonTypes.forEach((noon) => {
          let flag = true;
          if (employeeSecondmentNoon) {
            flag = canScheduling?.(employeeSecondmentNoon, noon);
          }
          if (flag) {
            noonPost[noon] = {
              departmentPostName: post.localLabel,
              departmentPostID: post.value,
              postType: post.type,
              attendanceDays: post.attendanceDays,
              color: post.color,
              backGroundColor: post.backGroundColor
            };
          }
        });
      }
      if (menuType === menuTypeEnum.MARK_MENU && data) {
        const markIndex = markList?.findIndex((mark) => mark.markID === data.markID);
        // 备注 特殊处理下
        if (data.markID === remarkID) {
          const employee = tableView.value.rows[rowIndex]?.employee;
          const column: TableColumn | undefined = tableView.value.columns.find((column) => column.index === startColumn);
          const params: Record<string, any> = {
            employeeName: employee.employeeName,
            rowIndex: rowIndex,
            date: datetimeUtil.formatDate(column?.value, "yyyy-MM-dd"),
            columnKey: column?.key,
            columnIndex: startColumn,
            markID: remarkID
          };
          editRemark?.(params);
        } else if (markIndex !== -1) {
          markList.splice(markIndex, 1);
        } else {
          markList.push(data);
        }
      }
      const isSunday = tableView.value.columns[startColumn!]?.isSunday;
      const newCellData: any = getCellData(noonPost, markList, noonList, undefined, backgroundColor, isSunday);
      await range?.setValue(newCellData);
      // 如果是排班画面，且不是借调，没有被借调，判断下是否有带教学生
      if (range && !isTemplate && (!employeeSecondmentNoon || !employeeSecondmentNoon[0])) {
        setStudentScheduling(newCellData, range!, sheet!);
      }
    };
  };
  /**
   * @description: 组装自定义菜单数据
   * @param configParams 配置参数
   * @return
   */
  const getCustomMenuData = (configParams: Record<string, any>) => {
    const { noonList, departmentPostList, shiftSchedulingMarkList, schedulingTemplateList } = configParams;
    const { templateKeyMap, postKeyMap, noonKeyMap, markKeyMap } = getKeyMaps();
    const menuItemCallback = getMenuItemCallback(noonList);
    // 排班岗位
    let departmentPostData: Record<string, any> = {
      value: "post",
      localLabel: "岗位",
      label: "部门岗位",
      icon: menuIconEnum.POST_MENU_ICON,
      children: []
    };
    // 休假岗位
    let restData: Record<string, any> = {
      value: "rest",
      localLabel: "休假",
      label: "休假岗位",
      icon: menuIconEnum.REST_MENU_ICON,
      children: []
    };
    let restPost: Record<string, any> | undefined = undefined;
    departmentPostList.forEach((departmentPost: Record<string, any>) => {
      if (departmentPost.type === restPostType) {
        restData.children.push({
          menuType: menuTypeEnum.REST_MENU,
          menuData: departmentPost,
          keyMap: postKeyMap,
          callback: menuItemCallback,
          getDisabled: (menuType: string, menuID: string | number, univerAPI: FUniver) => getMenuDisabled(menuType, menuID, univerAPI)
        });
        if (departmentPost.value === restPostID) {
          restPost = departmentPost;
        }
      } else {
        departmentPostData.children.push({
          menuType: menuTypeEnum.POST_MENU,
          menuData: departmentPost,
          keyMap: postKeyMap,
          callback: menuItemCallback,
          getDisabled: (menuType: string, menuID: string | number, univerAPI: FUniver) => getMenuDisabled(menuType, menuID, univerAPI)
        });
      }
    });
    let customMenuData: customMenuDataType[] = [
      { menuType: menuTypeEnum.POST_MENU, menuData: departmentPostData, keyMap: postKeyMap },
      { menuType: menuTypeEnum.REST_MENU, menuData: restData, keyMap: postKeyMap }
    ];
    // 休假菜单
    if (restPost) {
      const rest: Record<string, any> = common.clone(restPost as any);
      rest.icon = menuIconEnum.REST_BUTTON_MENU_ICON;
      customMenuData.splice(0, 0, {
        menuType: menuTypeEnum.REST_MENU,
        menuData: rest,
        keyMap: postKeyMap,
        callback: menuItemCallback
        // 工具栏的菜单只渲染一次，没有找到解决方案，暂时屏蔽
        // getDisabled: (menuType: string, menuID: string | number, univerAPI: FUniver) => getMenuDisabled(menuType, menuID, univerAPI)
      });
    }
    if (!isTemplate) {
      // 排班模板
      let templateData: Record<string, any> = {
        key: "schedulingTemplate",
        value: "排班模板",
        icon: menuIconEnum.TEMPLATE_MENU_ICON,
        children: []
      };
      schedulingTemplateList.forEach((template: Record<string, any>) => {
        templateData.children.push({
          menuType: menuTypeEnum.TEMPLATE_MENU,
          menuData: template,
          keyMap: templateKeyMap,
          callback: menuItemCallback,
          getDisabled: (menuType: string, menuID: string | number, univerAPI: FUniver) => getMenuDisabled(menuType, menuID, univerAPI)
        });
      });
      customMenuData.splice(0, 0, {
        menuType: menuTypeEnum.TEMPLATE_MENU,
        menuData: templateData,
        keyMap: templateKeyMap,
        callback: menuItemCallback
      });
    }
    noonList.forEach((noon: Record<string, any>) => {
      let noonDepartmentPostData = common.clone(departmentPostData);
      noonDepartmentPostData.label = noonDepartmentPostData.localLabel;
      noonDepartmentPostData.icon = "";
      let noonRestData = common.clone(restData);
      noonRestData.label = noonRestData.localLabel;
      noonRestData.icon = "";
      noonDepartmentPostData.children?.forEach((child: Record<string, any>) => {
        child.menuType = `${menuTypeEnum.NOON_MENU}-${menuTypeEnum.POST_MENU}-${noon.value}`;
      });
      noonRestData.children?.forEach((child: Record<string, any>) => {
        child.menuType = `${menuTypeEnum.NOON_MENU}-${menuTypeEnum.REST_MENU}-${noon.value}`;
      });
      let noontData: Record<string, any> = {
        value: `${noon.type}-${noon.value}`,
        label: noon.label,
        tooltip: `${noon.label}排班`,
        icon: noon.value === "1" ? menuIconEnum.AM_NOON_MENU_ICON : menuIconEnum.PM_NOON_MENU_ICON,
        children: [
          { menuType: `${menuTypeEnum.NOON_MENU}-${menuTypeEnum.POST_MENU}`, menuData: noonDepartmentPostData, keyMap: noonKeyMap },
          { menuType: `${menuTypeEnum.NOON_MENU}-${menuTypeEnum.REST_MENU}`, menuData: noonRestData, keyMap: noonKeyMap }
        ]
      };
      customMenuData.push({ menuType: menuTypeEnum.NOON_MENU, menuData: noontData, keyMap: noonKeyMap });
    });
    // 标记
    let markData: Record<string, any> = {
      markID: "mark",
      text: "排班标记",
      remark: "排班标记",
      icon: menuIconEnum.MARK_MENU_ICON,
      children: []
    };
    shiftSchedulingMarkList.forEach((mark: Record<string, any>) => {
      // 排班模板不显示备注标记
      if (isTemplate && mark.markID === remarkID) {
        return;
      }
      markData.children.push({
        menuType: menuTypeEnum.MARK_MENU,
        menuData: mark,
        keyMap: markKeyMap,
        callback: menuItemCallback,
        getDisabled: (menuType: string, menuID: string | number, univerAPI: FUniver) => getMenuDisabled(menuType, menuID, univerAPI),
        getActivated:
          mark.markID === remarkID
            ? undefined
            : (menuType: string, menuID: string | number, univerAPI: FUniver) => getMenuActivated(menuType, menuID, univerAPI)
      });
    });
    customMenuData.push({ menuType: menuTypeEnum.MARK_MENU, menuData: markData, keyMap: markKeyMap });
    return customMenuData;
  };
  /**
   * @description: 获取表格单元格显示内容
   * @param noonPost 排班数据
   * @param markList 排班标记列表
   * @param noonList 午别列表
   * @param restDay 休假天数
   * @param bgColor 背景色
   * @return
   */
  const getCellData = (
    noonPost: Record<string, Record<string, any>>,
    markList: Record<string, any>[],
    noonList: Record<string, string>[],
    restDay?: number,
    bgColor?: string,
    isSunday?: boolean
  ) => {
    let content: string = "";
    let backgroundColor: string = "";
    let textRuns: Record<string, any>[] = [];
    let paragraphs: Record<string, any>[] = [];
    // univerDoc段落样式-水平居中
    const paragraphStyle = { horizontalAlign: 2 };
    if (noonPost && Object.keys(noonPost).length) {
      let prePostID = -1;
      noonList.forEach((noon: Record<string, any>) => {
        const post = noonPost[noon.value];
        if (post) {
          // 背景色没值且当前岗位有值又不等白色时赋值
          if (!backgroundColor && post.backGroundColor && post.backGroundColor.toLowerCase() !== "#ffffff") {
            backgroundColor = post.backGroundColor;
          }
          let color = "";
          if (post.postType === restPostType) {
            color = post.schedulingRequestFlag ? "#ff0000" : "#ff00ff";
          } else {
            color = post.color || "#000000";
          }
          if (prePostID !== post.departmentPostID) {
            prePostID = post.departmentPostID;
            let postName = post.departmentPostName;
            if (post.postType === restPostType && restDay) {
              postName += restDay;
            }
            if (content && content !== "\r") {
              textRuns.push({
                st: content.length + 1,
                ed: content.length + postName.length + 1,
                ts: { cl: { rgb: color }, fs: 9 }
              });
              paragraphs.push({ paragraphStyle, startIndex: content.length + postName.length + 1 });
              content += `\r${postName}`;
            } else {
              textRuns.push({
                st: content.length,
                ed: content.length + postName.length,
                ts: { cl: { rgb: color }, fs: 9 }
              });
              paragraphs.push({ paragraphStyle, startIndex: content.length + postName.length });
              content += postName;
            }
          }
        } else if (content && content !== "\r") {
          // 如果上午有排班 换行 保证上午排班在上方显示
          content += "\r";
          paragraphs.push({ paragraphStyle, startIndex: 0 });
        } else {
          // 如果上午没有排班 换行 保证下午排班在下方显示
          content += "\r";
          paragraphs.push({ paragraphStyle, startIndex: 0 });
        }
      });
    }
    // 循环添加标记
    if (markList?.length) {
      // 按照sort升序排序
      sortByKeys(markList, ["sort"]);
      markList.forEach((mark: Record<string, any>) => {
        if (mark.icon) {
          textRuns.push({
            st: content.length,
            ed: content.length + mark.icon.length,
            ts: { cl: { rgb: mark.color || "#ff0000" }, fs: 9 }
          });
          content += mark.icon;
          if (paragraphs.length) {
            paragraphs[paragraphs.length - 1].startIndex = content.length;
          } else {
            paragraphs.push({ paragraphStyle, startIndex: content.length });
          }
        }
        if (mark.backGroundColor && mark?.backGroundColor?.toLowerCase() !== "#ffffff") {
          backgroundColor = mark.backGroundColor;
        }
      });
    }
    let univerDocData = { body: { dataStream: `${content}\r\n`, textRuns, paragraphs } };
    const style = { ...common.clone(cellBaseStyle), bg: { rgb: bgColor || backgroundColor } };
    // 周日右侧边框加粗
    if (isSunday) {
      style.bd.r.s = 13;
    }
    return {
      p: univerDocData,
      s: style,
      custom: { noonPost, markList }
    };
  };
  /**
   * @description: 获取借调/被借调背景色
   * @param row 行
   * @param data 行数据
   * @return
   */
  const getSecondBackGroundColor = (row: Record<string, any>, data: Record<string, any>) => {
    let backgroundColor: string | undefined = undefined;
    // 借调人员对应日期的背景色
    if (row.employee?.secondmentList?.length) {
      if (data?.secondmentFlag) {
        backgroundColor = "#fae8e6";
      } else {
        // 非借调日期标灰，表示不可修改
        backgroundColor = "#eeeeee";
      }
    }
    // 被借调，即借调出去
    if (data.secondedFlag) {
      backgroundColor = "#d0eafb";
    }
    return backgroundColor;
  };
  /**
   * @description: 初始化单元格数据
   * @param params 参数
   * @param noonList 午别列表
   * @param getRestDay 获取休假天数的方法
   * @return
   */
  const initCellData = (params: Record<string, any>, noonList: Record<string, string>[], getRestDay?: Function) => {
    const { data, rowIndex, columnIndex, row } = params;
    let backgroundColor: string | undefined = undefined;
    // 人员列
    if (!isTemplate && columnIndex < 2) {
      let value: Record<string, any> = { v: data, s: "cell-style" };
      // 借调人员列背景色
      if (row.employee?.secondmentList?.length) {
        backgroundColor = "#fae8e6";
      }
      // 被借调人员背景色
      if (row.employee?.secondedList?.length) {
        backgroundColor = "#d0eafb";
      }
      if (backgroundColor) {
        value.s = { ...cellBaseStyle, bg: { rgb: backgroundColor } };
      }
      return value;
    }
    // 获取休假天数
    let restDay = undefined;
    if (getRestDay) {
      restDay = getRestDay(rowIndex, columnIndex);
    }
    backgroundColor = getSecondBackGroundColor(row, data);
    const isSunday = tableView.value.columns[columnIndex]?.isSunday;
    return getCellData(data.noonPost, data.markList, noonList, restDay, backgroundColor, isSunday);
  };
  return {
    /**
     * @description: 初始化Univer表格配置参数并返回
     * @param configParams 配置参数
     * @return
     */
    initUniverConfig(configParams: Record<string, any>) {
      let initConfig = getConfig();
      const customMenuData = getCustomMenuData(configParams);
      return {
        ...initConfig,
        // 允许最大列数
        maxColumnCount: configParams.maxColumnCount,
        // 自定义右键菜单数据集合
        customMenuData: customMenuData,
        // 自定义菜单图标集合
        customMenuIcons: markRaw(univerMenuIcons)
      };
    },
    /**
     * @description: 将排班模板数据表转换为univer单元格数据格式
     * @param rowCount 行数
     * @param columnCount 列数
     * @param noonList 午别
     * @return
     */
    tableConvertCellData(rowCount: number, columnCount: number, noonList: Record<string, string>[], getRestDay?: Function) {
      return tableViewConvertCellData(rowCount, columnCount, tableView.value, (params: Record<string, any>) =>
        initCellData(params, noonList, getRestDay)
      );
    },
    /**
     * @description: 设置带的学生的排班
     */
    setStudentScheduling,
    /**
     * @description: 获取单元格内容
     */
    getCellData,
    /**
     * @description: 获取借调/被借调人员的背景色
     */
    getSecondBackGroundColor
  };
}
